<?php
namespace Cocolait;
use think\Db;
use think\Session;
/**
 * 邮箱管理类 无需继承任何类
 * Created by PhpStorm.
 * User: Cocolait
 * Date: 2016/12/12
 * Time: 15:30
 * 博  客：http://www.mgchen.com
 */
final class CpEmail{
    /**
     * 发送邮件 仅供 send_email()方法使用
     * @param  string $address 需要发送的邮箱地址 发送给多个地址需要写成数组形式
     * @param  string $subject 标题
     * @param  string $content 内容
     * @return boolean         是否成功
     */
     private static function send($address,$subject,$content) {
        //加载文件
        require_once EXTEND_PATH  . "Cocolait/class.phpmailer.php";
        require_once EXTEND_PATH  . "Cocolait/class.smtp.php";
        $data = Db::name('options')->where(['option_name'=>'邮箱配置'])->find();
        if (!$data) return ["error"=>1,"message"=>'邮箱配置不完整'];
        $data = json_decode($data['option_value'],true);
        //加载文件
        $phpmailer=new \Phpmailer();
        // 设置PHPMailer使用SMTP服务器发送Email
        $phpmailer->IsSMTP();
        // 设置为html格式
        $phpmailer->IsHTML(true);
        // 设置邮件的字符编码'
        $phpmailer->CharSet='UTF-8';
        // 设置SMTP服务器。
        $phpmailer->Host=$data['smtp'];
        // 设置为"需要验证"
        $phpmailer->SMTPAuth=true;
        // 设置发件箱帐号
        $phpmailer->Username=$data['send_account'];
        // 设置授权密码
        $phpmailer->Password=$data['send_password'];
        // 设置邮件头的From字段。
        $phpmailer->From=$data['send_account'];
        // 设置发件人名字
        $phpmailer->FromName=$data['send_name'];
        // 添加收件人地址，可以多次使用来添加多个收件人
        if(is_array($address)){
            foreach($address as $addressv){
                $phpmailer->AddAddress($addressv);
            }
        }else{
            $phpmailer->AddAddress($address);
        }
        // 设置邮件标题
        $phpmailer->Subject=$subject;
        // 设置邮件正文
        $phpmailer->Body=$content;
        // 发送邮件。
        if(!$phpmailer->Send()) {
            $phpmailererror=$phpmailer->ErrorInfo;
            return ["error"=>1,"message"=>$phpmailererror];
        }else{
            return ["error"=>0];
        }
     }

    /**
     * 支持多场景多模块发送邮箱
     * @param $username 用户名
     * @param $email    邮箱
     * @param int $type 发送模板类型 1:发送邮箱验证码 2：发送邮箱链接（点击链接） 3.发送邮箱到作者
     * @param string $display_name 邮箱模板名称 目前支持 ：'邮箱发送验证码,邮箱发送链接,邮箱发送评论回复'; [TODO :: 可扩展]
     * @param string $article 发送评论回复的数组 ['article_id'=>'文章ID','toName'=>'评论者名称','comment'=>'评论回复内容','comment_id'=>'评论者ID']
     * @param string $article 邮箱发送链接的数组 ['uid'=>'用户uid','check_type'=>'验证类型','webUrl'=>'网站域名地址不带http/https']
     * 数组定义的字段必须严格写入,不支持自定义,除非你修改了源代码
     * @return array
     */
     public static function send_email($username,$email,$type,$display_name,$article = [], $linkData = []) {
        if (!$username && !$email && !$type && !$display_name) return ['error'=>1,'msg'=>'参数错误'];
        $template = Db::name('email_display')->where(['display_name'=>$display_name])->find();
        if(!$template){
            return [
                'msg' => '邮箱模板不存在',
                'error' => 1
            ];
        } else if (!$template['is_status']) {
            return [
                'msg' => '邮箱模板处理关闭状态',
                'error' => 1
            ];
        }
        $options = json_decode($template['content'], true);
        //邮件标题
        $title = $options['title'];
        //邮件内容
        $content = $options['content'];
        $send_result = [];
        //发送邮箱验证码处理
        if ($type == 1) {
            $title .= "-邮箱验证码";
            $scene = "subEmailCode";             //验证的场景
            $annotation = '邮箱发送验证码';      //场景注释
            $Code = (string) CpMsubstr::rand_string(6,1);
            $replace_content = str_replace(['#username#','#code#'],[$username,$Code],$content);
            $send_result = self::send($email, $title, $replace_content);
            if (!$send_result['error']) {
                $data = [
                    'email' => (string) $email,
                    'sub_time' => time(),
                    'code' => (string) $Code,
                    'check_item' => $email . "_" . $Code . "_" . $scene,
                    'scene'     => $annotation
                ];
                Db::name('check_email')->insert($data);
                return ['error'=>0,'msg'=>'邮件发送成功'];
            }
        }

        //发送邮箱链接处理
        if ($type == 2) {
            if (!$linkData['uid'] && !$linkData['webUrl'] && !$linkData['check_type']) {
                return ['error'=>1,'msg'=>'参数错误'];
            }
            //邮箱验证token
            $token = self::_encrypt_code($linkData['uid'],$email);
            //需要替换url 这里写具体的逻辑处理地址
            if (empty($linkData['webUrl'])) {
                // 测试专用
                $url = "www.cms.com/h-check-email/{$token}/{$linkData['check_type']}.html";
            } else {
                // TODO
                $url = "{$linkData['webUrl']}/token/{$token}";
            }
            $exp = '';
            switch($linkData['check_type']){
                case 1:
                    $exp = "邮箱注册";
                    $title .= "-邮箱注册";
                    break;
                case 2:
                    $exp = "邮箱找回密码";
                    $title .= "-邮箱找回密码";
                    break;
                case 3:
                    $exp = "绑定邮箱";
                    $title .= "-绑定邮箱";
                    break;

            }
            $replace_content = str_replace(array('#username#','#link#','#ext_title#'), array($username,$url,$exp),$content);
            $send_result = self::send($email, $title, $replace_content);
            //发送成功,写入数据库作为处理
            if (!$send_result['error']) {
                Db::name('check_email_sublink')->where(['uid'=>$linkData['uid'],'type'=>$linkData['check_type']])->delete();
                //记录信息
                $checkData  = array(
                    'uid' => $linkData['uid'],
                    'token' => $token,
                    'status' => 0,
                    'add_time' => time(),
                    'type' => $linkData['check_type'],
                    'url' => "http://" . $url,
                    'state' => $exp
                );
                Db::name('check_email_sublink')->insert($checkData);
                return ['error'=>0,'msg'=>'邮件发送成功'];
            }
        }

        //发送邮箱评论回复处理
        if ($type == 3) {
            if (!$article['article_id'] && !$article['toName'] && !$article['comment'] && !$article['comment_id']) {
                return ['error'=>1,'msg'=>'参数错误'];
            }
            //检测评论者是否是发布者本人 跟发布者ID对比 获取后台Session数据
            if ($article['comment_id'] == Session::get('uid')) {
                return ['error'=>2,'msg'=>'邮箱不能发给自己'];
            }
            //获取文章标题,发布者ID
            $aData = DB::name('article')->where(['aid'=>$article['article_id']])->field(['title','users_uid'])->find();
            //获取发布者的用户名 和 邮箱
            $uData = DB::name('admin')->where(['uid'=>$aData['users_uid']])->field('username,email')->find();
            //检测发布者的邮箱
            if (!$uData['email']) {
                return ['error'=>2,'msg'=>'发布者邮箱为空,无法发送！'];
            }
            $title .= "-评论回复";
            $webUrl = "http://www.mgchen.com/a/{$article['article_id']}.html";
            $replace_content = str_replace(['#username#','#toname#','#titleName#','#content#','#link#'],[$uData['uname'],$article['toName'],$aData['title'],$article['comment'],$webUrl],$content);
            $send_result = self::send($uData['email'], $title, $replace_content);
        }

        //检测发送状态
        if($send_result['error']){
            return [
                'msg' => '邮件发送失败,请重试...',
                'error' => 1
            ];
        }
     }

    /**
     * 验证邮箱验证码
     * @param $phone 验证邮箱号码
     * @param $code  短信验证码
     * @param $scene  验证场景标识
     * @return bool
     */
     public static function check($email,$code,$scene) {
        if (empty($email) || empty($code)) return ['error'=>1,'msg'=>'参数错误'];
        $check_item = $email . "_" . $code . "_" . $scene;
        if ($old = Db::name('check_email')->where(['check_item' => $check_item,'is_del'=>0])->find()) {
            //验证通过
            //计算时间 分钟
            $time = round((time() - $old['sub_time']) / 60);
            if ($time > 30) {
                return ['error'=>1,'msg'=>'验证码已过期'];
            }
            //修改状态
            Db::name('check_email')->where(['id'=>$old['id']])->update([
                'check_time' => time(),
                'is_check' => 1
            ]);
            return ['error'=>0,'msg'=>'验证码成功'];
        } else {
            return ['error'=>1,'msg'=>'验证码失败'];
        }
     }

    /**
     * 验证邮箱发送链接
     * @param $token 邮箱发送url自带生成的token 验证的token  【获取方式 $this->request->param('token')】
     * @param $type  邮箱发送url自带生成的type  发送的类型   【获取方式 $this->request->param('token')】
     * @param string $table 用户表名
     * @param array $field  用户表需要取的字段 ['uid'=>'用户ID','username'=>'用户名'] 字段名称如不一致自行更改
     * @return array ['error'=>'状态码','msg'=>'提示信息'] error : 1 操作错误提示 2: 多次验证,提示建议 0：验证成功
     */
     public static function check_linkEmail ($token,$type,$table = 'admin',$field = ['uid','username']) {
        if (!$token && !$type) return ['error'=>1,'msg'=>'参数错误'];
        if ($token && $type) {
            //检测该key是否存在
            $data = Db::name('check_email_sublink')->where(['token'=>$token,'type'=>$type])->find();
            if ($data) {
                $userData = Db::name($table)->where(array('uid'=>$data['uid']))->field($field)->find();
                //防止重复点击
                if ($data['status']) {
                    if (Session::get('uid')){
                        return ['error'=>2,'msg'=>'邮箱url重复点击,建议跳转到首页'];
                    } else {
                        Session::clear();
                        Session::destroy();
                        Session::set('uid',$userData['uid']);
                        Session::set('username',$userData['username']);
                        return ['error'=>2,'msg'=>'邮箱url重复点击,建议跳转到首页'];
                    }
                }

                //邮箱注册 激活
                if ($data['type'] == 1 || $data['type'] == 2 || $data['type'] == 3) {
                    $status1 = Db::name('check_email_sublink')->where(['id'=>$data['id']])->setField('status',1);
                    if ($status1) {
                        return ['error'=>0,'msg'=>'验证成功'];
                    } else {
                        return ['error'=>3,'msg'=>'数据操作有误,建议跳转到首页'];
                    }
                }

                // TODO 具体业务,具体扩展

            } else {
                return ['error'=>1,'msg'=>'token错误,非法操作'];
            }
        } else {
            //不存在token 视为非法操作 直接跳转首页
            return ['error'=>1,'msg'=>'token错误,非法操作'];
        }
     }


    /**
     * 加密key
     * @param $uid
     * @param $email
     * @param string $key
     * @return string
     */
    private static function _encrypt_code($uid,$email,$key = 'www.mgchen.com') {
        $rand = CpMsubstr::rand_string(8);
        return md5(md5(md5($uid . $email . $rand . $key)));
    }
}